home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / OS Utilities / SnapshotSample1.0b3 / SnapshotSample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-22  |  10.8 KB  |  392 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:                SnapshotSample.c
  3.  
  4.     Contains:        Code for saving and restoring desktop icons.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. /*
  22.     This sample, when run the first time, creates a 
  23.     snapshot file in the Preferences folder which contains a list 
  24.     of the names and locations fo the items on the 
  25.     desktop.
  26.     
  27.     Running the sample again will read the snapshot
  28.     file and tell the Finder to position the items
  29.     at the locations read from the snapshot file.
  30.     
  31.     Sample does not read/set location of Trash,
  32.     nor of mounted volumes.
  33.     
  34.     Sample is provided as is... I didn't get much 
  35.     chance to test beyond the standard, "oh, this
  36.     works!" stage.
  37.     
  38.     The original Pascal version was written by
  39.     Quinn "The Eskimo!" and released as a Freeware
  40.     utility.  This DTS sample was created by
  41.     Deborah Grits.  This version was tidied up
  42.     and released by Quinn "The Eskimo!".
  43.     
  44.     Oh what a tangled web we weave...
  45. */
  46.     
  47. #include <AppleEvents.h>
  48. #include <Errors.h>
  49. #include <Events.h>
  50. #include <Fonts.h>
  51. #include <GestaltEqu.h>
  52. #include <Memory.h>
  53. #include <Menus.h>
  54. #include <OSUtils.h>
  55. #include <QDOffscreen.h>
  56. #include <QuickDraw.h>
  57. #include <Resources.h>
  58. #include <Script.h>
  59. #include <ToolUtils.h>
  60. #include <Windows.h>
  61.  
  62. //////////////////////////////////////////////////////////////////////////
  63. // Basic Utilities
  64.  
  65. static OSErr FindProcessByTypeAndCreator(OSType typeToFind, OSType creatorToFind, ProcessSerialNumber *processSN)
  66.     // Runs through the process list looking for the indicated application.
  67. {
  68.     OSErr err;
  69.         ProcessInfoRec infoRecToFill;
  70.         
  71.         err = noErr;
  72.     processSN->lowLongOfPSN = kNoProcess;
  73.     processSN->highLongOfPSN = kNoProcess;
  74.       infoRecToFill.processInfoLength = sizeof(ProcessInfoRec);
  75.       infoRecToFill.processName = nil;
  76.       infoRecToFill.processAppSpec = nil;
  77.     do {
  78.         err = GetNextProcess(processSN);
  79.         if (err == noErr) {
  80.             GetProcessInformation(processSN, &infoRecToFill);
  81.         }
  82.     } while ((infoRecToFill.processSignature != creatorToFind || infoRecToFill.processType != typeToFind) ||
  83.                    err != noErr);
  84.     
  85.     return(err);
  86. }
  87.  
  88. //////////////////////////////////////////////////////////////////////////
  89. // Global Types
  90.  
  91. // The snapshot file is made up of records of SnapRecord type.
  92. // An empty record (ie with name == "") is used to indicate
  93. // the end of the file.
  94.  
  95. typedef struct 
  96. {
  97.     Str63 name;
  98.     Point loc;
  99. } SnapRecord, *SnapRecordPtr, **SnapRecordHandle;
  100.  
  101.  
  102. //////////////////////////////////////////////////////////////////////////
  103. // Global Variables
  104.  
  105. // Used to tell the main event loop to quit.
  106.  
  107. static Boolean gQuit = false;
  108.  
  109. // An empty AppleEvent Descriptor.
  110.  
  111. const static AEDesc gNullDesc = {typeNull, nil};
  112.  
  113. //////////////////////////////////////////////////////////////////////////
  114. // Restoring Snapshots
  115.  
  116. static OSErr SetItemPosition(Str255 fname, Point dest, AEDesc *setDataEvent)
  117.     // Sends an AppleEvent to the targetDesc (which should target the Finder)
  118.     //  to set the position of the item whose name is fname to the position dest.
  119. {
  120.     OSErr                                err;
  121.     AEDesc                            fileNameDesc                 = gNullDesc;
  122.     AEDesc                            rootDesc                         = gNullDesc;
  123.     AEDesc                            propertyDescriptor     = gNullDesc;
  124.     AEDesc                            objParentDesc             = gNullDesc;
  125.     AEDesc                            objDesc                         = gNullDesc;
  126.     AEDesc                            reply                             = gNullDesc;
  127.     AEDesc                            newData                         = gNullDesc;
  128.     DescType                        procDescData                 = 'posn';
  129.  
  130.     // Create fileNameDesc to hold the file name, ief "xxx"
  131.     err = AECreateDesc(typeChar, &fname[1], *fname, &fileNameDesc);
  132.     
  133.     // Create objParentDesc to specify the parent object, ie item "xxxx" of application
  134.     if (err == noErr) {
  135.         err = CreateObjSpecifier(cItem, &rootDesc, formName, &fileNameDesc, false, &objParentDesc);
  136.     }
  137.  
  138.     // Create propertyDescriptor to hold the property specifier, ie position
  139.     if (err == noErr) {
  140.         err = AECreateDesc(typeType, &procDescData, sizeof(procDescData), &propertyDescriptor);
  141.     }
  142.     
  143.     // Create objDesc to reference the data to set, ie position of item "xxx" of application
  144.     if (err == noErr) {
  145.         err = CreateObjSpecifier(cQDPoint, &objParentDesc, formPropertyID, &propertyDescriptor, false, &objDesc);
  146.     }
  147.  
  148.     // Create on descriptor to hold the new data, ie the new icon position.
  149.     if (err == noErr) {
  150.         err = AECreateDesc(typeQDPoint, (void*)&dest, sizeof(dest), &newData);
  151.     }
  152.  
  153.     // Fill out the parameters, putting the objDesc into the direct object and the new data
  154.     //  into the data parameter.
  155.     if (err == noErr) {
  156.         err = AEPutParamDesc(setDataEvent, keyDirectObject, &objDesc);
  157.     }
  158.     if (err == noErr) {
  159.         err = AEPutParamDesc(setDataEvent, keyAEData, &newData);
  160.     }
  161.  
  162.     // Send the event.
  163.     if (err == noErr) {
  164.         err = AESend(setDataEvent, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
  165.     }
  166.  
  167.     // Clean up all those messy descriptors.  Don't you just love AppleEvents (-:
  168.     AEDisposeDesc(&rootDesc);
  169.     AEDisposeDesc(&fileNameDesc);
  170.     AEDisposeDesc(&objParentDesc);
  171.     AEDisposeDesc(&propertyDescriptor);
  172.     AEDisposeDesc(&objDesc);
  173.     AEDisposeDesc(&newData);
  174.     
  175.     return err;
  176. }
  177.  
  178. static OSErr RestoreSnapshot (FSSpec snapFss)
  179.     // Restore the snapshot file specified by snapFss.
  180. {
  181.     OSErr                                err;
  182.     ProcessSerialNumber finderPSN;
  183.     AEDesc                            targetDesc         = gNullDesc;
  184.     AEDesc                            setDataEvent     = gNullDesc;
  185.     short                                snapFileRef;
  186.     Boolean                         done;
  187.     SnapRecord                    aSnapRecord;
  188.     long                                byteCount;
  189.  
  190.     snapFileRef = 0;
  191.     
  192.     // Find the Finder's ProcessSerialNumber and create the targetDesc for it.
  193.   err = FindProcessByTypeAndCreator('FNDR', 'MACS', &finderPSN);
  194.   if (err == noErr) {
  195.     err = AECreateDesc(typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(finderPSN), &targetDesc);
  196.   }
  197.     // Create the AppleEvent.
  198.     if (err == noErr) {
  199.             err = AECreateAppleEvent(kAECoreSuite, kAESetData, &targetDesc,
  200.                                                                 kAutoGenerateReturnID, kAnyTransactionID, &setDataEvent);
  201.     }    
  202.     
  203.     // Open the file.
  204.     if (err == noErr) {
  205.         err = FSpOpenDF(&snapFss, fsRdPerm, &snapFileRef);
  206.     }
  207.     if (err == noErr) {
  208.         
  209.         // Read the records in the file, repositioning the icons as we go.
  210.         done = false;
  211.         do {
  212.             byteCount = sizeof(SnapRecord);
  213.             err = FSRead(snapFileRef, &byteCount, (void*) &aSnapRecord);
  214.             
  215.             if (err == noErr) {
  216.                 // We're done if we hit the empty string.
  217.                 done = (aSnapRecord.name[0] == 0);
  218.                 
  219.                 if (!done) {
  220.                     // Reposition the icon.
  221.                     err = SetItemPosition(aSnapRecord.name, aSnapRecord.loc, &setDataEvent);
  222.                 }
  223.             }
  224.         } while (!done);
  225.     }
  226.     
  227.     if (err == eofErr) {
  228.         err = noErr;
  229.     }
  230.  
  231.     // clean up
  232.     if (snapFileRef != 0) {
  233.         (void) FSClose(snapFileRef);
  234.     }
  235.     AEDisposeDesc(&setDataEvent);
  236.     AEDisposeDesc(&targetDesc);
  237.         
  238.     return err;
  239. }
  240.  
  241. //////////////////////////////////////////////////////////////////////////
  242. // Creating Snapshots
  243.  
  244. static OSErr WriteFileRecord(short snapFileRef, Str63 itemName, Point itemPosition)
  245.     // Add a new record to the snapshot file.
  246. {
  247.     OSErr                err;
  248.     SnapRecord    aSnapRecord;
  249.     long                byteCount;
  250.     
  251.     BlockMoveData(itemName, aSnapRecord.name, sizeof(aSnapRecord.name));
  252.     aSnapRecord.loc = itemPosition;
  253.     
  254.     byteCount = sizeof(SnapRecord);
  255.     err = FSWrite(snapFileRef, &byteCount, (void*) &aSnapRecord);
  256.     
  257.     return err;
  258. }
  259.  
  260. static OSErr CreateSnapshotFile(FSSpec snapFss)
  261.     // Add the positions for the icons on the desktop to the snapshot file snapFss.
  262. {
  263.     OSErr                 err;
  264.     short                    snapFileRef;
  265.     short                    deskVRefNum;
  266.     long                    deskDirID;
  267.     CInfoPBRec        pb;
  268.     short                    fileIndex;
  269.     Point                    folderOrigin;
  270.     Point                    itemPosition;
  271.     Str63                    itemName;
  272.  
  273.     snapFileRef = 0;
  274.     
  275.     // Find the desktop folder.
  276.     err = FindFolder(kOnSystemDisk, kDesktopFolderType, true, &deskVRefNum, &deskDirID);
  277.     
  278.     // Get the origin for the desktop folder.
  279.     pb.dirInfo.ioNamePtr = nil;
  280.     pb.dirInfo.ioDrDirID = deskDirID;
  281.     pb.dirInfo.ioVRefNum = deskVRefNum;
  282.     pb.dirInfo.ioFDirIndex = -1;        // get information about ioDirID
  283.     err = PBGetCatInfoSync(&pb);
  284.     if (err == noErr) {
  285.         folderOrigin.h = 0;
  286.         folderOrigin.v = 0;
  287.         folderOrigin.v = folderOrigin.v - 20;            // evil fudge factor!
  288.     }
  289.  
  290.     // Open up the snapshot file.
  291.     if (err == noErr) {
  292.         err = FSpOpenDF(&snapFss, fsRdWrPerm, &snapFileRef);
  293.     }
  294.  
  295.     // Loop through each file in the folder, adding it to the snapshot file.
  296.     if (err == noErr) {
  297.         fileIndex = 1;
  298.         do {
  299.                 pb.dirInfo.ioNamePtr = (StringPtr) itemName;
  300.                 pb.dirInfo.ioDrDirID = deskDirID;
  301.                 pb.dirInfo.ioVRefNum = deskVRefNum;
  302.                 pb.dirInfo.ioFDirIndex = fileIndex;
  303.                 err = PBGetCatInfoSync(&pb);
  304.                 if (err == noErr) {
  305.                     itemPosition = pb.hFileInfo.ioFlFndrInfo.fdLocation;
  306.                     SubPt(folderOrigin, &itemPosition);
  307.                     err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  308.                 }
  309.                 fileIndex += 1;
  310.         } while (err == noErr);
  311.         
  312.         // Write the sentinel to the end of the file.
  313.         if (err == fnfErr) {
  314.             itemName[0] = 0;
  315.             itemPosition.h = 0;
  316.             itemPosition.v = 0;
  317.             err = WriteFileRecord(snapFileRef, itemName, itemPosition);
  318.         }
  319.     }
  320.         
  321.     // Clean up.
  322.     if (snapFileRef != 0) {
  323.         (void) FSClose(snapFileRef);
  324.     }
  325.         
  326.     return err;
  327. }
  328.  
  329. //////////////////////////////////////////////////////////////////////////
  330. // Main Line
  331.  
  332. static void InitToolbox()
  333.     // Standard Macintosh toolbox init.
  334. {
  335.     InitGraf(&qd.thePort);
  336.     InitFonts();
  337.     InitWindows();
  338.     InitMenus();
  339.     TEInit();
  340.     InitDialogs(nil);
  341.     MaxApplZone();
  342.     
  343.     MoreMasters();
  344.     MoreMasters();
  345.     MoreMasters();
  346.  
  347.     InitCursor();
  348.     FlushEvents(0, everyEvent);    
  349. }
  350.  
  351. void main(void)
  352.     // The application's main entry point.
  353. {
  354.     OSErr     err;
  355.     FSSpec    snapFss;
  356.     long        gestaltResponse;
  357.  
  358.     // First, a quick check to make sure we have Scriptable Finder.  If we don't
  359.     //  we bail quickly.
  360.     
  361.     if ((Gestalt(gestaltFinderAttr, &gestaltResponse) != noErr) || ((gestaltResponse & (1 << gestaltOSLCompliantFinder)) == 0)) {
  362.         DebugStr("\pWhoops, no Scriptable Finder.");
  363.         ExitToShell();
  364.     }
  365.  
  366.     // Now bring up the standard Mac toolbox.
  367.     InitToolbox();
  368.     
  369.     // Find the Preferences folder.
  370.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, false, &(snapFss.vRefNum), &(snapFss.parID));
  371.  
  372.     if (err == noErr) {
  373.  
  374.         // Open the snapshot file in the Preferences folder.
  375.         //  Should get this from a resource, of course.
  376.         
  377.         (void) FSMakeFSSpec(snapFss.vRefNum, snapFss.parID, "\pDesktop Snap", &snapFss);
  378.         err = FSpCreate(&snapFss, 'FRøG', 'FRøG', 0);
  379.         
  380.         if (err == dupFNErr) {                                    // If we already have a snapshot file,
  381.             err = RestoreSnapshot(snapFss);                //  restore icon positions,
  382.         } else if (err == noErr) {                            // otherwise make a snapshot file.
  383.             // Create the snapshot file for the desktop
  384.             err = CreateSnapshotFile(snapFss);
  385.         }
  386.     }
  387.     
  388.     if (err != noErr) {
  389.         DebugStr("\pSnapshotter failed.");
  390.     }
  391. }
  392.